#pragma once

#include "..\\ExternalTools\\ExternalTools.h"

#include "..\\Loirey\\loirey_GLOBAL.h"
#include "..\\Loirey\\loirey_BasicStructure.h"

#include "..\\Classification.Base\cl_base_Data.h"
#include "..\\Classification.Base\cl_base_BinaryClassification.h"

using namespace loirey;

class CAdaBoostTrainingEndCondition
{
public:
	int MaxWcAmount;
	double TrainDR;
	double TrainFPR;

public:
	CAdaBoostTrainingEndCondition();
	CAdaBoostTrainingEndCondition(int MaxWcAmount);
	CAdaBoostTrainingEndCondition(int MaxWcAmount, double TrainDR, double TrainFPR);
	virtual void myInit();
	virtual void myInit(int MaxWcAmount);
	virtual void myInit(int MaxWcAmount, double TrainDR, double TrainFPR);
};

class CAdaBoostParameterConfig
{
public:
	int SFC_BinAmount;
	double SFC_FeatureSampleRate;
	bool fDetermineLayerThresholdUsingValSet;
	int DataSetUpdatingFrequency;
public:
	bool fOutputTrainLogToScreen;
	bool fOutputTrainLogToLogStream;

public:
	CAdaBoostParameterConfig();
};

class CSingleFeatureClassifier
{
public:
	int FeatureIndex;
	double Threshold;
	int Sgn;

	double ErrorRate;
	double alpha;
	double beta;

public:
	static void BuildValueHistogram(
		CDataSetForBinaryClassification* pDataSet, CBinaryClassificationExampleList& BinFlagExampleList,
		int FeatureIndex,
		CBoundedValueHistogram& dstPosValueHist, CBoundedValueHistogram& dstNegValueHist
		);
	void TrainByCertainFeature(
		CDataSetForBinaryClassification* pDataSet, CBinaryClassificationExampleList& TrainExampleList,
		const CAdaBoostParameterConfig& Parameters, int FeatureIndex
		);
	bool InputFromStream(istream& inStream);
	void OutputToStream(ostream& outStream);
	void Train(
		CDataSetForBinaryClassification* pDataSet, CBinaryClassificationExampleList& TrainExampleList,
		const CAdaBoostParameterConfig& Parameters,
		ostream& oLog)
		;
	void Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction);
};

static double GetKthSmallestWeight(vector<double>& rgValue, int K);

class CAdaBoostTrainingResultForPosNegExampleList
{
protected:
	int _PosExampleAmount;
	int _NegExampleAmount;
	double _PosExampleSumWeight;
	double _NegExampleSumWeight;
public:
	vector<int> rgPosExampleIndex;
	vector<int> rgNegExampleIndex;
	vector<double> rgPosExampleConfidence;
	vector<double> rgNegExampleConfidence;
	vector<double> rgPosExampleOriginalWeight;
	vector<double> rgNegExampleOriginalWeight;
	CBinaryClassificationResult_ByPrediction ClassificationResult_ByPrediction;
	CBinaryClassificationResult_ByConfidence ClassificationResult_ByConfidence;
	double CascadeDR;
	double CascadeFPR;

public:
	virtual void myInit(CBinaryClassificationExampleList& PosNegExampleList);
public:
	virtual void RunTest(double CascadeThreshold);
	//virtual void OutputToStream(ostream& outStream);
	virtual void OutputToStream_w(ostream& outStream);
public:
	virtual void MakeList(CBinaryClassificationExampleList& DstBinaryExampleList);
};

class CAdaBoostClassifier : public CBinaryClassifier
{
public:
	int TotalTrainedWeakLearnerAmount;
public:
	int WcAmount;
	vector<CSingleFeatureClassifier> rgWc;
	double CascadeThreshold;
	double AlphaSum;

	//vector<double> resRgPosTrainExampleConfidence;
	//vector<double> resRgNegTrainExampleConfidence;
	//vector<double> resRgPosValExampleConfidence;
	//vector<double> resRgNegValExampleConfidence;

	//CBinaryClassificationResult_ByPrediction resCR_Train;
	//CBinaryClassificationResult_ByPrediction resCR_Val;

	//double resCascadeDR_Train;
	//double resCascadeFPR_Train;
	//double resCascadeDR_Val;
	//double resCascadeFPR_Val;

public:
	virtual ~CAdaBoostClassifier() { }

	virtual bool InputFromStream(istream& inStream);
	virtual void OutputToStream(ostream& outStream);

	virtual void TrainNextLevel(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		const CAdaBoostParameterConfig& Parameters,
		CAdaBoostTrainingResultForPosNegExampleList& TrainDetails,
		ostream& oLog
		);
	static double GetThreshold_i(
		const vector<double>& rgPosExampleConfidence, const vector<double>& rgNegExampleConfidence,
		double paraDR
		);
	static double GetThreshold_w(
		CAdaBoostTrainingResultForPosNegExampleList& TrainDetails,
		double paraDR
		);

	virtual void Train(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		const CAdaBoostParameterConfig& Parameters, int WeakClassiferAmount, ostream& oLog);
	virtual void Train(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		CDataSetForBinaryClassification* pValDataSet, CBinaryClassificationExampleList& ValExampleList,
		const CAdaBoostParameterConfig& Parameters, int WeakClassiferAmount, ostream& oLog);
	virtual void Train(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		const CAdaBoostParameterConfig& Parameters,  const CAdaBoostTrainingEndCondition& EndCondition, ostream& oLog);
	virtual void Train(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		CDataSetForBinaryClassification* pValDataSet, CBinaryClassificationExampleList& ValExampleList,
		const CAdaBoostParameterConfig& Parameters,  const CAdaBoostTrainingEndCondition& EndCondition, ostream& oLog);
	virtual void Train(
		CDataSetForBinaryClassification* pTrainDataSet, CBinaryClassificationExampleList& TrainExampleList,
		CDataSetForBinaryClassification* pValDataSet, CBinaryClassificationExampleList& ValExampleList,
		const CAdaBoostParameterConfig& Parameters, const CAdaBoostTrainingEndCondition& EndCondition,
		CAdaBoostTrainingResultForPosNegExampleList& TrainDetails, CAdaBoostTrainingResultForPosNegExampleList& ValDetails,
		ostream& oLog
		);
protected:
	virtual void _Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction);
public:
	virtual void Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction);
};

